home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / examples / demo / demosrc / d_morph.pro < prev    next >
Text File  |  1997-07-08  |  16KB  |  495 lines

  1. ; $Id: d_morph.pro,v 1.8 1997/04/22 21:10:53 dave Exp $
  2. ;
  3. ;  Copyright (c) 1997, Research Systems, Inc. All rights reserved.
  4. ;       Unauthorized reproduction prohibited.
  5. ;
  6. ;+
  7. ;  FILE:
  8. ;       d_morph.pro
  9. ;
  10. ;  CALLING SEQUENCE: d_morph
  11. ;
  12. ;  PURPOSE:
  13. ;       Morph 2 images.
  14. ;
  15. ;  MAJOR TOPICS: Visualization and data analysis
  16. ;
  17. ;  CATEGORY:
  18. ;       IDL 5.0
  19. ;
  20. ;  INTERNAL FUNCTIONS and PROCEDURES:
  21. ;       fun barycentric         -  Compute the barycentric matrix.
  22. ;       pro morph               -  Compute the morhing imges
  23. ;       pro morph_demo_event    -  Event handler
  24. ;       pro morphCleanup        -  Cleanup
  25. ;       pro d_morph          -  Main procedure
  26. ;
  27. ;  EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
  28. ;
  29. ;       NONE
  30. ;
  31. ;  REFERENCE: IDL Reference Guide, IDL User's Guide
  32. ;
  33. ;  NAMED STRUCTURES:
  34. ;       none.
  35. ;
  36. ;  COMMON BLOCS:
  37. ;       morph_demo_common
  38. ;
  39. ;  MODifICATION HISTORY:
  40. ;       DS   - Written.
  41. ;-
  42.  
  43. forward_function people_image
  44.  
  45. ;----------------------------------------------------------------------------
  46. ;
  47. ;  Purpose:  Compute and returns the barycentric matrix.
  48. ;
  49. function barycentric, $
  50.     x, $
  51.     y, $
  52.     xt, $
  53.     yt, $
  54.     zt
  55.     det = (xt(1)-xt(0)) * (yt(2)-yt(0)) - (xt(2)-xt(0)) * (yt(1)-yt(0))
  56.     w0 = ((xt(1)-x) * (yt(2)-y) - (xt(2)-x) * (yt(1)-y)) / det
  57.     w1 = ((xt(2)-x) * (yt(0)-y) - (xt(0)-x) * (yt(2)-y)) / det
  58.     w2 = ((xt(0)-x) * (yt(1)-y) - (xt(1)-x) * (yt(0)-y)) / det
  59.     PRINT, w0, w1, w2
  60.     RETURN,w0 * zt(0) + w1 * zt(1) + w2 * zt(2)
  61. end
  62.  
  63. ;----------------------------------------------------------------------------
  64. ;
  65. ;  Purpose:  This procedure actually does the morphing.
  66. ;
  67. pro morph, $
  68.     i0, $            ; IN: first image
  69.     i1, $            ; IN: seconsd image
  70.     x0, $            ; IN: x control point of first image
  71.     y0, $            ; IN: y control point of first image
  72.     x1, $            ; IN: x control point of second image
  73.     y1, $            ; IN: y control point of second image
  74.     nsteps, $        ; IN: number of transitions, including the 2 end images
  75.     QUINTIC = quint  ; IN: (opt) indicates quintic interpolation.
  76.  
  77.     ncp = N_ELEMENTS(x0)
  78.     if ( (ncp NE N_ELEMENTS(y0)) OR (ncp NE N_ELEMENTS(x1)) OR $
  79.     (ncp NE N_ELEMENTS(y1)) ) then $
  80.     MESSAGE, "Number of control points doesn't match"
  81.  
  82.     TRIANGULATE, x0, y0, tr, bounds
  83.     TRIANGULATE, x1, y1, tr1, bounds1
  84.  
  85.     s = SIZE(i0)
  86.     t = SIZE(i1)
  87.     if (s(0) NE 2) OR (t(0) NE 2) OR (s(1) NE t(1)) OR (s(2) NE t(2)) then $
  88.     MESSAGE,'Image dimensions inconsistent'
  89.     nx = s(1)
  90.     ny = s(2)
  91.  
  92.     gs = [1,1]
  93.     b = [0,0,nx-1, ny-1]
  94.  
  95.     if (N_ELEMENTS(quint) EQ 0) then quint = 0
  96.  
  97.     ;  Call for the xinteranimate tool to display
  98.     ;  the sequence of images.
  99.     ;
  100.     xinteranimate, set=[nx, ny, nsteps], /SHOWLOAD, /CYCLE
  101.  
  102.     for i=0, nsteps-1 do begin        ;Each step
  103.     t = FLOAT(i) / FLOAT(nsteps-1)  ;From 0.0 to 1.0
  104.     xt = x0 + (x1-x0) * t        ;From 1st to 2nd
  105.     yt = y0 + (y1-y0) * t
  106.     xt1 = x1 + t * (x0-x1)        ;From 2nd to 1st
  107.     yt1 = y1 + t * (y0-y1)
  108.     im1 = INTERPOLATE(i1, $
  109.         TRIGRID(x0,y0,xt1,tr, gs, b, QUINT=quint), $
  110.         TRIGRID(x0,y0,yt1,tr, gs, b, QUINT=quint))
  111.     im0 = INTERPOLATE(i0, $
  112.         TRIGRID(x1,y1,xt1,tr, gs, b, QUINT=quint), $
  113.         TRIGRID(x1,y1,yt1,tr, gs, b, QUINT=quint))
  114.     im = BYTE(t * im1  + (1.0-T) * im0)
  115.     xinteranimate, image=im, frame=i
  116.     endfor
  117. end
  118.  
  119.  
  120. ;----------------------------------------------------------------------------
  121. ;
  122. ;  Purpose:  Main event handler.
  123. ;
  124. pro d_morph_event, $
  125.     sEvent     ; IN: event Structure
  126.  
  127.     common morph_demo_common, cmd_button, frames_button, msg, lun, image_in, $
  128.     draw, draw_size, im_size, dwin, sx, nx, state, iindex, imlt, imrt, $
  129.     ncp, cpx, cpy, nimages, offsets, nframes
  130.  
  131.     ;  Set to the morphing window.
  132.     ;
  133.     WSET, dwin    
  134.  
  135.     ;  Brancjh accoridingly to the event.
  136.     ;
  137.     case sEvent.id of
  138.  
  139.         ;  Handle a mouse button event occuring in the viewing area.
  140.         ;
  141.         frames_button: nframes = ([3,8,16,32])(sEvent.index)
  142.  
  143.         draw: begin
  144.  
  145.             ;  Returns if it is not a button press event.
  146.             ;
  147.             if (sEvent.press NE 0) then RETURN 
  148.  
  149.             ;  Selecting an image
  150.             ;
  151.             if (state LE 1) then begin
  152.                 im = ((draw_size > !d.y_size) - sEvent.y) / $
  153.                     sx * nx + sEvent.x / sx
  154.             iindex(state) = im
  155.             if (state EQ 0) then WIDGET_CONTROL, msg, $
  156.                     SET_VALUE='Select other image' $
  157.             else begin
  158.                 WIDGET_CONTROL, msg, SET_VALUE='Pick LEFT control point' 
  159.                 erase
  160.                 for i=0,1 do begin
  161.                     imrt = people_image(iindex(i), lun, offsets, $
  162.                        LABEL=msg, /BW, REQUIRED=im_size)
  163.                 TV, CONGRID(imrt, draw_size, draw_size), i*draw_size, 0
  164.                 if (i EQ 0) then imlt = imrt
  165.             endfor
  166.                 endelse
  167.             state = state + 1
  168.             ncp = 0
  169.  
  170.             ;  Must be marking a control point (CP).
  171.             ;
  172.             endif else begin    
  173.  
  174.                 ;  Right image case.
  175.                 ;
  176.             rt = (sEvent.x GE draw_size)
  177.  
  178.                 ;  Scale to pixels.
  179.                 ;
  180.             x = (sEvent.x MOD draw_size) * im_size / $
  181.                     draw_size 
  182.             y = sEvent.y * im_size / draw_size
  183.  
  184.                 ;  If not the proper image, toss it.
  185.                 ;
  186.             if (rt NE (ncp AND 1)) then RETURN 
  187.  
  188.                 ;  Mark the control point.
  189.                 ;
  190.                 PLOTS, sEvent.x, sEvent.y, /DEVICE, $
  191. ;                    COLOR=!D.N_COLORS-1, PSYM=2
  192.                     COLOR=!D.TABLE_SIZE-1, PSYM=2
  193.             empty
  194.  
  195.                 ;  First control point, else it is the second.
  196.                 ;
  197.             if ncp EQ 0 then begin
  198.                 cpx = x
  199.                 cpy = y
  200.             endif else begin
  201.                 cpx = [cpx, x]
  202.                 cpy = [cpy, y]
  203.             endelse
  204.  
  205.             ncp = ncp + 1
  206.  
  207.                 ;  Refreash the message text.
  208.                 ;
  209.             WIDGET_CONTROL, msg, SET_VALUE= $
  210.                 'Mark the ' + (['LEFT','RIGHT'])(ncp and 1) + ' image.'
  211.  
  212.             if (!Version.Os NE 'MacOS') then $
  213.                     TVCRS, sEvent.x - (2*rt-1) * draw_size, sEvent.y, /DEVICE $
  214.                 else TVCRS, 1
  215.             endelse
  216.  
  217.         endcase      ;   of  draw
  218.  
  219.         cmd_button: begin
  220.  
  221.             ;  Branch to the approriate command button event.
  222.             ;
  223.             case sEvent.value of
  224.  
  225.                 ;  Quit this application.
  226.                 ;
  227.                 'Done': begin
  228.                 if (image_in EQ 0) then FREE_LUN, lun
  229.                 WIDGET_CONTROL, sEvent.top, /DESTROY
  230.             endcase   ;  of Done
  231.  
  232.                 'Help': begin
  233.                 XDISPLAYFILE, GROUP=sEvent.top, $
  234.                     DONE_BUTTON='Done', $
  235.                     WIDTH=55, HEIGHT=14, $
  236.                     TITLE='Morph Demo Help', TEXT= [ $
  237.                     "Morphing is the gradual and continuous changing of ", $
  238.                     "one image to another.  This demonstration shows", $
  239.                     "IDL's built-in irregular gridding, interpolation", $
  240.                     "and image processing capabilities by changing", $
  241.                     "one person's face to another.", $
  242.                     " ", $
  243.                     "To run this demo, select two images with the same", $
  244.                     "general orientation. Then alternately mark control", $
  245.                     "points on the same feature in each image.", $
  246.                     "For example, the tip of the nose, corners of the", $
  247.                     "lips, pupils of the eyes, and top of the head are", $
  248.                     "readily distinguished features of human faces.",$
  249.                     " More control points give better results.", $
  250.                     " ", $
  251.                     "When all points are marked, press the 'Go' button", $
  252.                     "to morph between the images.  You can experiment", $
  253.                     "by adding OR removing control points, and", $
  254.                     "stop and restart the animatation."]
  255.             endcase  ;  of  Help
  256.  
  257.                 ;  Remove the previous control points.
  258.                 ;
  259.                 'Delete CP': begin
  260.  
  261.                     ;  Return under certain conditions.
  262.                     ;
  263.                 if (state LE 1) then RETURN
  264.                 if (ncp LE 0) then RETURN
  265.  
  266.                     ;  Verify the validity of this event and handle it.
  267.                     ;
  268.                 ncp = (ncp + (ncp and 1)) - 2
  269.  
  270.                     ;  If valid, set the control points.
  271.                     ;
  272.                 if (ncp gt 0) then begin
  273.                     cpx = cpx(0:ncp-1)
  274.                     cpy = cpy(0:ncp-1)
  275.                     endif
  276.  
  277.                 TV, CONGRID(imlt, draw_size, draw_size), 0, 0
  278.                 TV, CONGRID(imrt, draw_size, draw_size), draw_size, 0
  279.  
  280.                 for i=0, ncp-1 do $
  281.                     PLOTS, cpx(i) * draw_size / $
  282.                             im_size + (i and 1) * draw_size, $
  283.                 cpy(i) * draw_size / im_size, /DEVICE, $
  284. ;                        PSYM=2, COLOR=!D.N_COLORS-1
  285.                         PSYM=2, COLOR=!D.TABLE_SIZE-1
  286.  
  287.                 WIDGET_CONTROL, msg, SET_VALUE= 'Mark the left image.'
  288.             endcase  ;  of Delete CP (control points)
  289.  
  290.                 ;  Restart the whole process.
  291.                 ;
  292.                 'Restart': begin    
  293.                 ERASE
  294.                 ncp = 0      ; number o fcontrol points.
  295.  
  296.                 if (image_in) then begin
  297.                     TV, CONGRID(imlt, draw_size, draw_size), 0, 0
  298.                     TV, CONGRID(imrt, draw_size, draw_size), draw_size, 0
  299.                 endif else begin
  300.                     TV, people_image(nimages, lun, offsets, LABEL=msg, /BW)
  301.                     state = 0
  302.                 endelse
  303.             endcase    ;  of Restart
  304.  
  305.                 ;  Start the animation sequence.
  306.                 ;
  307.                 'Go' :  begin
  308.  
  309.                     ;  Show the hourglass during the processing of the event.
  310.                     ;
  311.                     WIDGET_CONTROL, sEvent.top, /HOURGLASS
  312.  
  313.                     ;  Return if the number of control points is less
  314.                     ;  than 2 or the xinteranimate tool is already running.
  315.                     ;
  316.                 if (ncp LT 2) then RETURN
  317.                 if (XREGISTERED("XInterAnimate")) then RETURN
  318.  
  319.                 i2 = indgen(ncp/2) * 2        ;Alternate CPs
  320.                 i1 = im_size -1
  321.                 x0 = [cpx(i2), 0, i1, i1, 0]        ;Add corners to CPs
  322.                 x1 = [cpx(i2+1), 0, i1, i1, 0]
  323.                 y0 = [cpy(i2), 0, 0, i1, i1]
  324.                 y1 = [cpy(i2+1), 0, 0, i1, i1]
  325.                 morph, imlt, imrt, x0, y0, x1, y1, nframes
  326.                 xinteranimate, 40, group = sEvent.top
  327.             endcase   ;  of Go
  328.  
  329.             endcase  ;    of sEvent.value
  330.  
  331.         endcase    ;  of cmd_button
  332.  
  333.         else: i2=0      ;  Dummy statement.
  334.  
  335.     endcase   ;  of sEvent.id
  336. end
  337. ;-----------------------------------------------------------------
  338. ;
  339. ;    PURPOSE : Cleanup procedure. Restore colortable.
  340. ;
  341. pro morphCleanup, wTopBase
  342.  
  343.     WIDGET_CONTROL, wTopBase, GET_UVALUE=sState, /NO_COPY
  344.  
  345.     if (WIDGET_INFO(sState.group, /VALID_ID)) then begin
  346.         WIDGET_CONTROL, sState.group, SENSITIVE=1
  347.     endif
  348.  
  349.     ;  Restore the color table.
  350.     ;
  351.     TVLCT, sState.colorTable
  352.     imlt = 0 & imrt = 0         ;Clean up images
  353. end   ;  of morphCleanup
  354.  
  355. ;----------------------------------------------------------------------------
  356. ;
  357. ;  Purpose:  Main procedure. This application  aplies mophing of 2 images.
  358. ;
  359. pro d_morph, $
  360.     GROUP=Group, $              ; IN: (opt) group leader identifier
  361.     im0, $                      ; IN: first image
  362.     im1, $                      ; IN: second image
  363.     USE_CURRENT=use_current, $  ; IN: (opt) use files in current directory
  364.     FROM_PEOPLE=from_people     ; IN: (opt) indicate for use of people demo.
  365.  
  366.     ;+
  367.     ; Demo for morphing.  If im0 and im1 are supplied, they are the two
  368.     ; images to morph.  If not supplied, the people.dat file is read and
  369.     ; the user selects two faces to morph.
  370.     ;    USE_CURRENT = true to read from files in current directory.
  371.     ;-
  372.  
  373.     common morph_demo_common
  374.  
  375.     nframes = 8
  376.     if N_ELEMENTS(group) eq 0 then group = 0L
  377.  
  378.     if (group ne 0) then WIDGET_CONTROL, group, SENSITIVE=0 
  379.  
  380.     ;  Get the current color vectors to restore
  381.     ;  when this application is exited.
  382.     ;
  383.     TVLCT, savedR, savedG, savedB, /GET
  384.  
  385.     ;  Build color table from color vectors
  386.     ;
  387.     colorTable = [[savedR],[savedG],[savedB]]
  388.  
  389.     ;  Loads people demo , the people images, etc...
  390.     ;
  391.     if (N_ELEMENTS(im_size) EQ 0 and KEYWORD_SET(from_people) EQ 0) then begin
  392.         if 0 then d_people      ;This makes sure we get .sav files right
  393.        resolve_routine, 'd_people'
  394.     endif
  395.  
  396.     ;  Have only one instance of morph_demo running.
  397.     ;
  398.     if (xregistered("d_morph")) then return
  399.     im_size = 256
  400.     image_in = N_ELEMENTS(im0) gt 2
  401.  
  402.     ;  Initilize the image size and the size of the drawing area.
  403.     ;
  404.     if (image_in) then im_size = (SIZE(im0))(1) ;We're passed images
  405.     draw_size = 256 > im_size    ;Size of drawable
  406.  
  407.     ;  Initialize other working variables and arrays.
  408.     ;
  409.     state = 0
  410.     ncp = 0      ;  number of control points.
  411.     iindex = INTARR(2)
  412.  
  413.     ;  Create the widgets, starting with the top level base.
  414.     ;
  415.     Base = WIDGET_BASE(Title='Morphing', /ROW)
  416.  
  417.         ;  Create the left base containing the control buttons
  418.         ;  and the message text.
  419.         ;
  420.     left = WIDGET_BASE(base, /COLUMN)
  421.  
  422.     cmd_button = CW_BGROUP(left, /NO_REL, $
  423.                            /RETURN_NAME, /COL, /FRAME, $
  424.                            ['Done', 'Help', 'Restart', 'Delete CP', 'Go'])
  425.  
  426.     frames_button = WIDGET_DROPLIST(left, VALUE= ['3', '8', '16', '32'], $
  427.                                     /FRAME, TITLE='Frames')
  428.     WIDGET_CONTROL, frames_button, SET_DROPLIST_SELECT=1
  429.  
  430.             msg = WIDGET_TEXT(left, XSIZE=20, YSIZE=1, $
  431.             VALUE=(['Select two images', $
  432.                          'Mark the left image.'])(image_in))
  433.  
  434.         siz = [draw_size*2, draw_size]
  435.         DEVICE, get_screen=x
  436.  
  437.         if (NOT image_in) then siz = siz > ([384, 512])(x(0) gt 640)
  438.  
  439.         ;  Create the drawing area.
  440.         ;
  441.         draw = WIDGET_DRAW(base, xsize=siz(0), ysize=siz(1), /BUTTON_EVENTS)
  442.  
  443.     ;  Realize the widgets.
  444.     ;
  445.     WIDGET_CONTROL, base, /REALIZE
  446.  
  447.     WIDGET_CONTROL, draw, GET_VALUE=dwin
  448.     WSET, dwin
  449.  
  450.     ;  Load the grey scale color table.
  451.     ;
  452.     loadct, 0
  453.  
  454.     ;  Display the initial images.
  455.     ;
  456.     if (image_in EQ 0) then begin  ;Initial display
  457.         read_people_index, names, offsets, USE_CURRENT=use_current
  458.         nimages = N_ELEMENTS(names)
  459.         nx = SQRT(nimages)          ;# of images across
  460.         if (nx NE fix(nx)) then nx = nx + 1
  461.         nx = fix(nx)
  462.         sx = min(siz) / nx        ;Size of image
  463.         filename = 'people.jpg'
  464.         if (KEYWORD_SET(use_current) EQ 0) then $
  465.         ;filename = demopath(filename, subdir='images')
  466.             filename = filepath(filename, SUBDIR=['examples','data'])
  467.  
  468.         OPENR, lun, /GET, filename, /STREAM
  469.  
  470.         TV, people_image(nimages, lun, offsets, $
  471.             LABEL=msg, /BW, REQUIRED=min(siz))
  472.  
  473.     ;  Images passed in case.
  474.     ;
  475.     endif else begin            ;Images passed in
  476.         state=2
  477.         imlt = im0
  478.         imrt = im1
  479.         TV, CONGRID(imlt, draw_size, draw_size), 0
  480.         TV, CONGRID(imrt, draw_size, draw_size), 1
  481.     endelse
  482.  
  483.     ;  Create the state structure.
  484.     ;
  485.     sState = { $
  486.         ColorTable:colorTable, $
  487.         Group: group $
  488.     }
  489.  
  490.     WIDGET_CONTROL, Base, SET_UVALUE=sState, /NO_COPY
  491.  
  492.     Xmanager, 'd_morph', base, GROUP_LEADER=group, $ ;  , /NO_BLOCK
  493.       CLEANUP='morphCleanup'
  494. end
  495.